﻿using BaseicModuleExpression.Model;
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace BaseicModuleExpression.DBExtend
{
    /// <summary>
    /// 解析表达式目录树
    /// </summary>
    public class ParseExpression : ExpressionVisitor
    {
        private Stack<string> strings = new Stack<string>();
        public ParseExpression()
        {

        }

        public string LinqToSql<T>(Expression<Func<T, bool>> expression)
        {
            Visit(expression);
            string sql = string.Concat(strings.ToArray());
            return sql;
        }
        public string LinqToSql<T,P>(Expression<Func<T, P>> expression)
        {
            Visit(expression);
            string sql = string.Concat(strings.ToArray());
            return sql;
        }

        [return: NotNullIfNotNull("node")]
        public override Expression? Visit(Expression? node)
        {
            return base.Visit(node);
        }

        /// <summary>
        /// 二元表达式
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitBinary(BinaryExpression node)
        {
            //Expression<Func<People, bool>> lambda = x => x.Age > 5
            //                                            && x.Id < 5//;
            //                                            && x.Id == 3
            //                                            && x.Name.StartsWith("1")
            //                                            && x.Name.EndsWith("1")
            //                                            && x.Name.Contains("1");
            //x.id >5 && x.id <5  
            strings.Push(")");
            this.Visit(node.Right); //x.Name.Contains("1")
            strings.Push($" {SqlOperator.ToSqlOperator(node.NodeType)} ");
            this.Visit(node.Left);
            strings.Push("(");
            return node;
        }

        /// <summary>
        /// 方法
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            #region
            {
                //if (m == null) throw new ArgumentNullException("MethodCallExpression");

                //string format;
                //switch (m.Method.Name)
                //{
                //    case "StartsWith":
                //        format = "({0} LIKE {1}+'%')";
                //        break;

                //    case "Contains":
                //        format = "({0} LIKE '%'+{1}+'%')";
                //        break;

                //    case "EndsWith":
                //        format = "({0} LIKE '%'+{1})";
                //        break;

                //    default:
                //        throw new NotSupportedException(m.NodeType + " is not supported!");
                //}
                //this.Visit(m.Object);
                //this.Visit(m.Arguments[0]);
                //string right = this._StringStack.Pop();
                //string left = this._StringStack.Pop();
                //this._StringStack.Push(String.Format(format, left, right));
            }
            #endregion
            string format;
            switch (node.Method.Name) //x.Name.Contains("1")
            {
                case "StartsWith":
                    format = " {0} LIKE '{1}%' ";
                    break;
                case "Contains":
                    format = " {0} LIKE '%{1}%' ";
                    break;

                case "EndsWith":
                    format = " {0} LIKE '%{1}' ";
                    break;
                default:
                    throw new NotSupportedException(node.NodeType + " is not supported!");
            }
            this.Visit(node.Arguments[0]); //参数
            this.Visit(node.Object); // member成员
            var member = strings.Pop(); //member成员
            var parper = strings.Pop();//参数
            var one = parper.Substring(2);
            one = one.Substring(0, one.Length - 2);
            var sql = string.Format(format, member, one);
            strings.Push(sql);
            return node;
        }

        /// <summary>
        /// 常量
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitConstant(ConstantExpression node)
        {
            if (node.Value.GetType() == typeof(int) || node.Value.GetType() == typeof(float) || node.Value.GetType() == typeof(decimal) || node.Value.GetType() == typeof(double))
                strings.Push($" {node.Value} ");
            else
                strings.Push($" '{node.Value}' ");
            return node;
        }

        /// <summary>
        ///  属性 字段
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitMember(MemberExpression node)
        {
            strings.Push($" [{node.Member.Name}] ");
            return node;
        }

        /// <summary>
        /// 参数
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override MemberBinding VisitMemberBinding(MemberBinding node)
        {
            //x => x.id > 5 &&  x.Age < 5
            return node;
        }

        /// <summary>
        /// 对象属性字段值绑定
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override MemberListBinding VisitMemberListBinding(MemberListBinding node)
        {
            return node;
        }

        ///// <summary>
        ///// 对象实列化
        ///// </summary>
        ///// <param name="node"></param>
        ///// <returns></returns>
        //protected override ElementInit VisitElementInit(ElementInit node)
        //{
        //    return node;
        //}

        /// <summary>
        /// 对象实列化
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitMemberInit(MemberInitExpression node)
        {
            base.VisitMemberInit(node);
            return node;
        }
    }
}
